package com.blb.edupayservice.service.impl;

import com.blb.common.entity.UserCourseOrder;
import com.blb.edupayservice.config.MyWXPayConfig;
import com.blb.edupayservice.config.RabbitMQConfig;
import com.blb.edupayservice.feign.CourseServiceFeignClient;
import com.blb.edupayservice.feign.OrderServiceFeignClient;
import com.blb.edupayservice.service.IWXPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.util.Streams;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 微信支付的实现
 */
@Slf4j
@Service
public class WXPayServiceImpl implements IWXPayService {

    public static final String DEVICE_INFO = "WEB";
    public static final String BODY = "泡泡教育";
    public static final String FEE_TYPE = "CNY";
    //回调接口的URL
    public static final String NOTIFY_URL = "http://kz2b3m.natappfree.cc/wxpay/callback";
    public static final String TRADE_TYPE = "NATIVE";
    public static final String SIGN = "5E00F9F72173C9449F802411E36208734B8138870ED3F66D8E2821D55B317078";

    @Autowired
    private CourseServiceFeignClient courseServiceFeignClient;

    @Autowired
    private OrderServiceFeignClient orderServiceFeignClient;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GlobalTransactional
    @Override
    public Map<String, String> makeWxOrder(Long userId, Long courseId, Long activityId, Long price) throws Exception {
        //创建支付对象
        MyWXPayConfig config = new MyWXPayConfig();
        WXPay wxPay = new WXPay(config);
        //配置微信支付
        Map<String, String> map = new HashMap<>();
        map.put("appid", config.getAppID());
        map.put("mch_id", config.getMchID());
        map.put("device_info", DEVICE_INFO);
        map.put("nonce_str", WXPayUtil.generateNonceStr());
        map.put("body", BODY);
        //创建随机订单号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        map.put("out_trade_no", tradeNo);
        map.put("fee_type", FEE_TYPE);
        //价格
        map.put("total_fee", String.valueOf(price));
        //微信对商户后台的回调接口，更新订单状态
        map.put("notify_url", NOTIFY_URL);
        map.put("trade_type", TRADE_TYPE);
        //商品id
        map.put("product_id", String.valueOf(activityId));
        //执行统一下单
        Map<String, String> result = wxPay.unifiedOrder(map);
        log.info("微信下单:{}" ,result);
        if(result != null) {
            //保存订单号
            result.put("trade_no", tradeNo);
            //创建课程订单
            Timestamp now = Timestamp.valueOf(LocalDateTime.now());
            UserCourseOrder order = new UserCourseOrder(System.currentTimeMillis(),userId,courseId,activityId,1L,0,tradeNo,price,now,now,0);
            orderServiceFeignClient.makeOrder(order);
            //减少课程库存
            courseServiceFeignClient.reduceStock(activityId);
//            int x = 10 / 0;
            //发送订单号，超时会进入死信队列
            rabbitTemplate.convertAndSend(RabbitMQConfig.ORDER_EXCHANGE,RabbitMQConfig.ORDER_QUEUE_KEY,tradeNo,
                    //消息的后置处理
                    message -> {
                        message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
                        //设置消息超时
                        message.getMessageProperties().setExpiration(String.valueOf(30 * 1000));
                        return message;
                    });
            log.info("完成下单，订单：{}",result);
        }
        return result;
    }

    @Override
    public void makeQRCode(String url, HttpServletResponse response) throws Exception {
        //通过支付链接生成二维码
        HashMap<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        hints.put(EncodeHintType.MARGIN, 2);
        //把code_url包装到二维码图片
        BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 200, 200, hints);
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", response.getOutputStream());
        log.info("创建二维码完成");
    }

    @Override
    public String checkWxOrder(String tradeNo) throws Exception {
        MyWXPayConfig config = new MyWXPayConfig();
        WXPay pay = new WXPay(config);
        Map<String, String> map = new HashMap<>();
        map.put("appid",config.getAppID());
        map.put("mch_id", config.getMchID());
        map.put("nonce_str", WXPayUtil.generateNonceStr());
        map.put("out_trade_no", tradeNo);
        map.put("sign",SIGN);
        //查询订单
        Map<String, String> res = pay.orderQuery(map);
        String state = res.get("trade_state");
        log.info("订单" + tradeNo + ",状态" + state);
        return state;
    }

    /**
     * 微信支付成功回调
     * @param request
     * @param response
     * @throws Exception
     */
    @Override
    public void wxpayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获得微信传来的xml字符串
        String str = Streams.asString(request.getInputStream());
        //将字符串xml转换为Map
        Map<String, String> map = WXPayUtil.xmlToMap(str);
        //给微信后台发送消息
        response.getWriter().println("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
        //读取订单号
        String tradeNo = map.get("out_trade_no");
        //查询课程id
        ResponseEntity<UserCourseOrder> entity = orderServiceFeignClient.getOrderByTradeNo(tradeNo);
        UserCourseOrder order = entity.getBody();
        //增加课程销量
        courseServiceFeignClient.addCourseSales(order.getCourseId());
        //修改订单状态为已支付
        order.setStatus(1);
        orderServiceFeignClient.changeOrderStatus(order);
        log.info("支付成功：{}",order);
    }
}
